Module Federation kullanarak frontend micro-frontend'lerine derinlemesine bir bakış: mimari, faydalar, uygulama stratejileri ve ölçeklenebilir web uygulamaları için en iyi pratikler.
Frontend Micro-Frontend: Module Federation Mimarisine Hakim Olmak
Günümüzün hızla gelişen web geliştirme dünyasında, büyük ölçekli frontend uygulamaları oluşturmak ve sürdürmek giderek daha karmaşık hale gelebilir. Geleneksel monolitik mimariler genellikle kod şişkinliği, yavaş derleme süreleri ve bağımsız dağıtımlardaki zorluklar gibi sorunlara yol açar. Micro-frontend'ler, frontend'i daha küçük, daha yönetilebilir parçalara ayırarak bir çözüm sunar. Bu makale, micro-frontend'leri uygulamak için güçlü bir teknik olan Module Federation'ı derinlemesine inceliyor; faydalarını, mimarisini ve pratik uygulama stratejilerini araştırıyor.
Micro-Frontend'ler Nedir?
Micro-frontend'ler, bir frontend uygulamasının daha küçük, bağımsız ve dağıtılabilir birimlere ayrıştırıldığı bir mimari tarzıdır. Her micro-frontend genellikle ayrı bir ekibe aittir, bu da daha fazla özerklik ve daha hızlı geliştirme döngüleri sağlar. Bu yaklaşım, backend'de yaygın olarak kullanılan microservices mimarisini yansıtır.
Micro-frontend'lerin temel özellikleri şunlardır:
- Bağımsız Dağıtılabilirlik: Her micro-frontend, uygulamanın diğer bölümlerini etkilemeden bağımsız olarak dağıtılabilir.
- Takım Özerkliği: Farklı takımlar, tercih ettikleri teknolojileri ve iş akışlarını kullanarak farklı micro-frontend'leri sahiplenebilir ve geliştirebilir.
- Teknoloji Çeşitliliği: Micro-frontend'ler farklı framework'ler ve kütüphaneler kullanılarak oluşturulabilir, bu da takımların iş için en iyi araçları seçmesine olanak tanır.
- İzolasyon: Micro-frontend'ler, zincirleme hataları önlemek ve kararlılığı sağlamak için birbirinden izole edilmelidir.
Neden Micro-Frontend Kullanmalı?
Bir micro-frontend mimarisini benimsemek, özellikle büyük ve karmaşık uygulamalar için birçok önemli avantaj sunar:
- Geliştirilmiş Ölçeklenebilirlik: Frontend'i daha küçük birimlere ayırmak, uygulamayı gerektiğinde ölçeklendirmeyi kolaylaştırır.
- Daha Hızlı Geliştirme Döngüleri: Bağımsız takımlar paralel olarak çalışabilir, bu da daha hızlı geliştirme ve yayınlama döngülerine yol açar.
- Artan Takım Özerkliği: Takımlar kodları üzerinde daha fazla kontrole sahip olur ve kararları bağımsız olarak alabilirler.
- Daha Kolay Bakım: Daha küçük kod tabanlarının bakımı ve hata ayıklaması daha kolaydır.
- Teknolojiden Bağımsız: Takımlar, kendi özel ihtiyaçları için en iyi teknolojileri seçebilir, bu da yenilik ve denemeye olanak tanır.
- Azaltılmış Risk: Dağıtımlar daha küçük ve daha sık olduğundan, büyük ölçekli başarısızlık riski azalır.
Module Federation'a Giriş
Module Federation, Webpack 5 ile tanıtılan ve JavaScript uygulamalarının çalışma zamanında diğer uygulamalardan dinamik olarak kod yüklemesine olanak tanıyan bir özelliktir. Bu, gerçekten bağımsız ve birleştirilebilir micro-frontend'lerin oluşturulmasını sağlar. Her şeyi tek bir pakette birleştirmek yerine, Module Federation farklı uygulamaların birbirlerinin modüllerini yerel bağımlılıklarmış gibi paylaşmasına ve kullanmasına izin verir.
Iframe'lere veya web bileşenlerine dayanan geleneksel micro-frontend yaklaşımlarının aksine, Module Federation kullanıcı için daha sorunsuz ve entegre bir deneyim sunar. Bu diğer tekniklerle ilişkili performans yükünü ve karmaşıklığı ortadan kaldırır.
Module Federation Nasıl Çalışır?
Module Federation, modülleri "paylaşma" (exposing) ve "kullanma" (consuming) konsepti üzerine çalışır. Bir uygulama ("host" veya "container") modülleri paylaşabilirken, diğer uygulamalar ("remote" olanlar) bu paylaşılan modülleri kullanabilir. İşte sürecin bir dökümü:
- Modül Paylaşımı: Webpack'te bir "remote" uygulama olarak yapılandırılan bir micro-frontend, belirli modülleri (bileşenler, fonksiyonlar, yardımcı programlar) bir yapılandırma dosyası aracılığıyla paylaşır. Bu yapılandırma, paylaşılacak modülleri ve bunlara karşılık gelen giriş noktalarını belirtir.
- Modül Kullanımı: Bir "host" veya "container" uygulama olarak yapılandırılan başka bir micro-frontend, remote uygulamayı bir bağımlılık olarak bildirir. Remote uygulamanın modül federasyon manifestosunun (paylaşılan modülleri açıklayan küçük bir JSON dosyası) bulunabileceği URL'yi belirtir.
- Çalışma Zamanı Çözümlemesi: Host uygulamanın remote uygulamadan bir modül kullanması gerektiğinde, remote uygulamanın modül federasyon manifestosunu dinamik olarak getirir. Webpack daha sonra modül bağımlılığını çözer ve gerekli kodu çalışma zamanında remote uygulamadan yükler.
- Kod Paylaşımı: Module Federation ayrıca host ve remote uygulamalar arasında kod paylaşımına da olanak tanır. Eğer her iki uygulama da paylaşılan bir bağımlılığın (ör. React, lodash) aynı sürümünü kullanıyorsa, kod paylaşılır, bu da tekrarlamayı önler ve paket boyutlarını küçültür.
Module Federation Kurulumu: Pratik Bir Örnek
Module Federation'ı iki micro-frontend içeren basit bir örnekle gösterelim: bir "Ürün Kataloğu" ve bir "Alışveriş Sepeti". Ürün Kataloğu, Alışveriş Sepeti'nin ilgili ürünleri göstermek için kullanacağı bir ürün listeleme bileşenini paylaşacaktır.
Proje Yapısı
micro-frontend-example/
product-catalog/
src/
components/
ProductList.jsx
index.js
webpack.config.js
shopping-cart/
src/
components/
RelatedProducts.jsx
index.js
webpack.config.js
Ürün Kataloğu (Remote)
webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const path = require('path');
module.exports = {
// ... diğer webpack yapılandırmaları
plugins: [
new ModuleFederationPlugin({
name: 'product_catalog',
filename: 'remoteEntry.js',
exposes: {
'./ProductList': './src/components/ProductList',
},
shared: {
react: { singleton: true, eager: true, requiredVersion: '^17.0.0' },
'react-dom': { singleton: true, eager: true, requiredVersion: '^17.0.0' },
},
}),
],
};
Açıklama:
- name: Remote uygulamanın benzersiz adı.
- filename: Paylaşılacak giriş noktası dosyasının adı. Bu dosya modül federasyon manifestosunu içerir.
- exposes: Bu uygulama tarafından hangi modüllerin paylaşılacağını tanımlar. Bu durumda, `src/components/ProductList.jsx` dosyasından `ProductList` bileşenini `./ProductList` adı altında paylaşıyoruz.
- shared: Host ve remote uygulamalar arasında paylaşılması gereken bağımlılıkları belirtir. Bu, kod tekrarını önlemek ve uyumluluğu sağlamak için çok önemlidir. `singleton: true`, paylaşılan bağımlılığın yalnızca bir örneğinin yüklenmesini sağlar. `eager: true`, paylaşılan bağımlılığı başlangıçta yükler, bu da performansı artırabilir. `requiredVersion`, paylaşılan bağımlılık için kabul edilebilir sürüm aralığını tanımlar.
src/components/ProductList.jsx
import React from 'react';
const ProductList = ({ products }) => (
{products.map((product) => (
- {product.name} - ${product.price}
))}
);
export default ProductList;
Alışveriş Sepeti (Host)
webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const path = require('path');
module.exports = {
// ... diğer webpack yapılandırmaları
plugins: [
new ModuleFederationPlugin({
name: 'shopping_cart',
remotes: {
product_catalog: 'product_catalog@http://localhost:3001/remoteEntry.js',
},
shared: {
react: { singleton: true, eager: true, requiredVersion: '^17.0.0' },
'react-dom': { singleton: true, eager: true, requiredVersion: '^17.0.0' },
},
}),
],
};
Açıklama:
- name: Host uygulamanın benzersiz adı.
- remotes: Bu uygulamanın modül kullanacağı remote uygulamaları tanımlar. Bu durumda, `product_catalog` adında bir remote bildiriyoruz ve `remoteEntry.js` dosyasının bulunabileceği URL'yi belirtiyoruz. Format `remoteName: 'remoteName@remoteEntryUrl'` şeklindedir.
- shared: Remote uygulamaya benzer şekilde, host uygulama da paylaşılan bağımlılıklarını tanımlar. Bu, host ve remote uygulamaların paylaşılan kütüphanelerin uyumlu sürümlerini kullanmasını sağlar.
src/components/RelatedProducts.jsx
import React, { useEffect, useState } from 'react';
import ProductList from 'product_catalog/ProductList';
const RelatedProducts = () => {
const [products, setProducts] = useState([]);
useEffect(() => {
// İlgili ürün verilerini getir (örneğin, bir API'den)
const fetchProducts = async () => {
// Gerçek API uç noktanızla değiştirin
const response = await fetch('https://fakestoreapi.com/products?limit=3');
const data = await response.json();
setProducts(data);
};
fetchProducts();
}, []);
return (
İlgili Ürünler
{products.length > 0 ? : Yükleniyor...
}
);
};
export default RelatedProducts;
Açıklama:
- import ProductList from 'product_catalog/ProductList'; Bu satır, `ProductList` bileşenini `product_catalog` remote'undan içe aktarır. `remoteName/moduleName` sözdizimi, Webpack'e modülü belirtilen remote uygulamadan getirmesini söyler.
- Bileşen daha sonra içe aktarılan `ProductList` bileşenini kullanarak ilgili ürünleri görüntüler.
Örneği Çalıştırma
- Hem Ürün Kataloğu hem de Alışveriş Sepeti uygulamalarını kendi geliştirme sunucularını kullanarak başlatın (ör. `npm start`). Farklı portlarda çalıştıklarından emin olun (ör. Ürün Kataloğu 3001 portunda ve Alışveriş Sepeti 3000 portunda).
- Tarayıcınızda Alışveriş Sepeti uygulamasına gidin.
- Ürün Kataloğu uygulamasından `ProductList` bileşeni tarafından oluşturulan İlgili Ürünler bölümünü görmelisiniz.
İleri Düzey Module Federation Kavramları
Temel kurulumun ötesinde, Module Federation, micro-frontend mimarinizi geliştirebilecek birkaç gelişmiş özellik sunar:
Kod Paylaşımı ve Sürümleme
Örnekte gösterildiği gibi, Module Federation, host ve remote uygulamalar arasında kod paylaşımına olanak tanır. Bu, Webpack'teki `shared` yapılandırma seçeneği ile elde edilir. Paylaşılan bağımlılıkları belirterek, kod tekrarını önleyebilir ve paket boyutlarını küçültebilirsiniz. Paylaşılan bağımlılıkların doğru şekilde sürümlendirilmesi, uyumluluğu sağlamak ve çakışmaları önlemek için çok önemlidir. Anlamsal Sürümleme (SemVer), yazılımı sürümlemek için yaygın olarak kullanılan bir standarttır ve uyumlu sürüm aralıkları tanımlamanıza olanak tanır (ör. `^17.0.0`, 17.0.0'a eşit veya daha büyük ancak 18.0.0'dan küçük herhangi bir sürüme izin verir).
Dinamik Remote'lar
Önceki örnekte, remote URL'si `webpack.config.js` dosyasında sabit kodlanmıştı. Ancak, birçok gerçek dünya senaryosunda, remote URL'sini çalışma zamanında dinamik olarak belirlemeniz gerekebilir. Bu, promise tabanlı bir remote yapılandırması kullanılarak elde edilebilir:
// webpack.config.js
remotes: {
product_catalog: new Promise(resolve => {
// Remote URL'sini bir yapılandırma dosyasından veya API'den al
fetch('/config.json')
.then(response => response.json())
.then(config => {
const remoteUrl = config.productCatalogUrl;
resolve(`product_catalog@${remoteUrl}/remoteEntry.js`);
});
}),
},
Bu, remote URL'sini ortama (ör. geliştirme, hazırlık, üretim) veya diğer faktörlere göre yapılandırmanıza olanak tanır.
Asenkron Modül Yükleme
Module Federation, asenkron modül yüklemeyi destekleyerek modülleri isteğe bağlı olarak yüklemenize olanak tanır. Bu, kritik olmayan modüllerin yüklenmesini erteleyerek uygulamanızın ilk yükleme süresini iyileştirebilir.
// RelatedProducts.jsx
import React, { Suspense, lazy } from 'react';
const ProductList = lazy(() => import('product_catalog/ProductList'));
const RelatedProducts = () => {
return (
İlgili Ürünler
Yükleniyor...}>
);
};
`React.lazy` ve `Suspense` kullanarak, `ProductList` bileşenini remote uygulamadan asenkron olarak yükleyebilirsiniz. `Suspense` bileşeni, modül yüklenirken bir yedek kullanıcı arayüzü (ör. bir yükleme göstergesi) sağlar.
Federasyon Stilleri ve Varlıkları
Module Federation, micro-frontend'ler arasında stilleri ve varlıkları paylaşmak için de kullanılabilir. Bu, uygulamanız genelinde tutarlı bir görünüm ve his sağlamaya yardımcı olabilir.
Stilleri paylaşmak için, bir remote uygulamadan CSS modüllerini veya styled component'leri paylaşabilirsiniz. Varlıkları (ör. resimler, fontlar) paylaşmak için, Webpack'i varlıkları paylaşılan bir konuma kopyalayacak şekilde yapılandırabilir ve ardından bunları host uygulamadan referans alabilirsiniz.
Module Federation için En İyi Pratikler
Module Federation'ı uygularken, başarılı ve sürdürülebilir bir mimari sağlamak için en iyi pratikleri takip etmek önemlidir:
- Net Sınırlar Tanımlayın: Sıkı bağımlılığı önlemek ve bağımsız dağıtılabilirliği sağlamak için micro-frontend'ler arasındaki sınırları net bir şekilde tanımlayın.
- İletişim Protokolleri Oluşturun: Micro-frontend'ler arasında net iletişim protokolleri tanımlayın. Olay otobüsleri, paylaşılan durum yönetimi kütüphaneleri veya özel API'ler kullanmayı düşünün.
- Paylaşılan Bağımlılıkları Dikkatli Yönetin: Sürüm çakışmalarını önlemek ve uyumluluğu sağlamak için paylaşılan bağımlılıkları dikkatli bir şekilde yönetin. Anlamsal sürümlemeyi kullanın ve npm veya yarn gibi bir bağımlılık yönetim aracı kullanmayı düşünün.
- Sağlam Hata Yönetimi Uygulayın: Zincirleme arızaları önlemek ve uygulamanızın kararlılığını sağlamak için sağlam hata yönetimi uygulayın.
- Performansı İzleyin: Darboğazları belirlemek ve performansı optimize etmek için micro-frontend'lerinizin performansını izleyin.
- Dağıtımları Otomatikleştirin: Tutarlı ve güvenilir dağıtımlar sağlamak için dağıtım sürecini otomatikleştirin.
- Tutarlı Bir Kodlama Stili Kullanın: Okunabilirliği ve sürdürülebilirliği artırmak için tüm micro-frontend'lerde tutarlı bir kodlama stili uygulayın. ESLint ve Prettier gibi araçlar bu konuda yardımcı olabilir.
- Mimarinizi Belgeleyin: Tüm ekip üyelerinin sistemi ve nasıl çalıştığını anlamasını sağlamak için micro-frontend mimarinizi belgeleyin.
Module Federation ve Diğer Micro-Frontend Yaklaşımları
Module Federation, micro-frontend'leri uygulamak için güçlü bir teknik olsa da, tek yaklaşım değildir. Diğer popüler yöntemler şunlardır:
- Iframe'ler: Iframe'ler, micro-frontend'ler arasında güçlü bir izolasyon sağlar, ancak sorunsuz bir şekilde entegre edilmeleri zor olabilir ve performans yükü oluşturabilirler.
- Web Bileşenleri: Web bileşenleri, farklı micro-frontend'lerde kullanılabilecek yeniden kullanılabilir UI öğeleri oluşturmanıza olanak tanır. Ancak, uygulanmaları Module Federation'dan daha karmaşık olabilir.
- Derleme Zamanı Entegrasyonu: Bu yaklaşım, tüm micro-frontend'leri derleme zamanında tek bir uygulamada birleştirmeyi içerir. Dağıtımı basitleştirebilse de, takım özerkliğini azaltır ve çakışma riskini artırır.
- Single-SPA: Single-SPA, birden çok tek sayfalık uygulamayı tek bir uygulamada birleştirmenize olanak tanıyan bir framework'tür. Derleme zamanı entegrasyonundan daha esnek bir yaklaşım sunar ancak kurulumu daha karmaşık olabilir.
Hangi yaklaşımın kullanılacağı, uygulamanızın özel gereksinimlerine ve ekibinizin büyüklüğüne ve yapısına bağlıdır. Module Federation, esneklik, performans ve kullanım kolaylığı arasında iyi bir denge sunarak birçok proje için popüler bir seçimdir.
Module Federation'ın Gerçek Dünya Örnekleri
Belirli şirket uygulamaları genellikle gizli olsa da, Module Federation'ın genel ilkeleri çeşitli endüstrilerde ve senaryolarda uygulanmaktadır. İşte bazı potansiyel örnekler:
- E-ticaret Platformları: Bir e-ticaret platformu, web sitesinin ürün kataloğu, alışveriş sepeti, ödeme süreci ve kullanıcı hesabı yönetimi gibi farklı bölümlerini ayrı micro-frontend'lere ayırmak için Module Federation'ı kullanabilir. Bu, farklı ekiplerin bu bölümler üzerinde bağımsız olarak çalışmasına ve platformun geri kalanını etkilemeden güncellemeler dağıtmasına olanak tanır. Örneğin, *Almanya*'daki bir ekip ürün kataloğuna odaklanırken, *Hindistan*'daki bir ekip alışveriş sepetini yönetebilir.
- Finansal Hizmetler Uygulamaları: Bir finansal hizmetler uygulaması, ticaret platformları ve hesap yönetimi gibi hassas özellikleri ayrı micro-frontend'lere izole etmek için Module Federation'ı kullanabilir. Bu, güvenliği artırır ve bu kritik bileşenlerin bağımsız olarak denetlenmesine olanak tanır. *Londra*'daki bir ekibin ticaret platformu özelliklerinde uzmanlaştığını ve *New York*'taki başka bir ekibin hesap yönetimini ele aldığını hayal edin.
- İçerik Yönetim Sistemleri (CMS): Bir CMS, geliştiricilerin özel modülleri micro-frontend'ler olarak oluşturmasına ve dağıtmasına olanak tanımak için Module Federation'ı kullanabilir. Bu, CMS kullanıcıları için daha fazla esneklik ve özelleştirme sağlar. *Japonya*'daki bir ekip özel bir resim galerisi modülü oluşturabilirken, *Brezilya*'daki bir ekip gelişmiş bir metin düzenleyici oluşturabilir.
- Sağlık Uygulamaları: Bir sağlık uygulaması, elektronik sağlık kayıtları (EHR'ler), hasta portalları ve faturalandırma sistemleri gibi farklı sistemleri ayrı micro-frontend'ler olarak entegre etmek için Module Federation'ı kullanabilir. Bu, birlikte çalışabilirliği artırır ve yeni sistemlerin daha kolay entegrasyonuna olanak tanır. Örneğin, *Kanada*'daki bir ekip yeni bir tele-sağlık modülünü entegre edebilirken, *Avustralya*'daki bir ekip hasta portalı deneyimini iyileştirmeye odaklanabilir.
Sonuç
Module Federation, micro-frontend'leri uygulamak için güçlü ve esnek bir yaklaşım sunar. Uygulamaların çalışma zamanında birbirlerinden dinamik olarak kod yüklemesine izin vererek, gerçekten bağımsız ve birleştirilebilir frontend mimarilerinin oluşturulmasını sağlar. Dikkatli planlama ve uygulama gerektirse de, artan ölçeklenebilirlik, daha hızlı geliştirme döngüleri ve daha fazla takım özerkliği gibi faydaları, onu büyük ve karmaşık web uygulamaları için cazip bir seçenek haline getirir. Web geliştirme dünyası gelişmeye devam ettikçe, Module Federation, frontend mimarisinin geleceğini şekillendirmede giderek daha önemli bir rol oynamaya hazırlanıyor.
Bu makalede özetlenen kavramları ve en iyi pratikleri anlayarak, günümüzün hızlı tempolu dijital dünyasının taleplerini karşılayan ölçeklenebilir, sürdürülebilir ve yenilikçi frontend uygulamaları oluşturmak için Module Federation'dan yararlanabilirsiniz.